<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of missparse
 *
 * @author soleman
 */
class missparse extends CI_Model {
    /**
     * Note for this code
     * 1. After loading a docs, it will return an array that consists of "no","title", and "content"
     * 2. For loading stop word, i make two function, first code returns an array of stop word, and second code returns regex format like a|b|c
     * 3. The second function is for reducing, so i must not implode in my regex formulation
     * 4. In this class also has a function for removing punctuation. The input is a string, and output is a string
     * 5. This also provides function for removing white space, so we can ensure that every word will be separated by a space from other words
     * 6. Use str_replace is better than preg_replace... Ohw, but str_replace can not have regex paremeter.
     * 7. For using, after loading documents, you should extract doc to remove reading mark. 
     */

    /**
     * default constuctor
     */
    public function __construct() {
        parent::__construct();
    }

    /**
     * =======================================FILE LOADER===============================================
     */

    /** FIX
     * parse docs to array of docs that consists of no, title, content
     * @param type $filename
     * @return type an array of object docs. The structure is "no","content"
     */
    public function docs_to_object_of_docs($filename) {
        $file = file_get_contents($filename);
        //parsed document into n documents
        $documents = explode(".I ", $file);
        //for each documents insert into array
        //1. Find the number of document
        //2. Find title, find content
        $i = 0;
        $docs;
        foreach ($documents as $document) {
            if ($document != "") {
                $number = explode(".T", $document);
                //$number[0] is a number documents
                $no = $number[0];
                $title = "";
                $content = "";
                //number[1]is consists of title and content
                $rawtitle = explode(".W", $number[1]);
                //after explode, if there is content size of $title must > 1
                //if size 1 it is only title
                if (sizeof($rawtitle) == 1) {
                    $title = $rawtitle[0];
                } else {
                    $title = $rawtitle[0];
                    $content = $rawtitle[1];
                }
                //Cleaning Process for title
                $title = explode("\n.A", $title);
                $title = explode("\n.B", $title[0]);
                $title = $title[0];
                //Cleaning for content
                $content = explode("\n.X", $content);
                $content = explode("\n.N", $content[0]);
                $content = explode("\n.A", $content[0]);
                $content = explode("\n.B", $content[0]);
                $content = $content[0];
                $docs[$i]->no = str_replace("\n", " ", $no);
                $docs[$i]->title = strtolower(str_replace("\n", " ", $title));
                $docs[$i]->content = strtolower(str_replace("\n", " ", $content));
                $i++;
            }
        }
        return $docs;
    }

    /** FIX
     * parse docs to array of docs that consists of no, title, content
     * @param type $filename
     * @return type an array of object docs. The structure is "no","content", and no reading mark again
     */
    public function docs_to_object_of_docs_clean($filename) {
        $file = file_get_contents($filename);
        //parsed document into n documents
        $documents = explode(".I ", $file);
        //for each documents insert into array
        //1. Find the number of document
        //2. Find title, find content
        $i = 0;
        $docs;
        foreach ($documents as $document) {
            if ($document != "") {
                $number = explode(".T", $document);
                //$number[0] is a number documents
                $no = $number[0];
                $title = "";
                $content = "";
                //number[1]is consists of title and content
                $rawtitle = explode(".W", $number[1]);
                //after explode, if there is content size of $title must > 1
                //if size 1 it is only title
                if (sizeof($rawtitle) == 1) {
                    $title = $rawtitle[0];
                } else {
                    $title = $rawtitle[0];
                    $content = $rawtitle[1];
                }
                //Cleaning Process for title
                $title = explode("\n.A", $title);
                $title = explode("\n.B", $title[0]);
                $title = $title[0];
                //Cleaning for content
                $content = explode("\n.X", $content);
                $content = explode("\n.N", $content[0]);
                $content = explode("\n.A", $content[0]);
                $content = explode("\n.B", $content[0]);
                $content = $content[0];
                $docs[$i]->no = $this->removing_white_space(str_replace("\n", " ", $no));
                $docs[$i]->title = strtolower($this->removing_white_space($this->remove_hypenated_text(str_replace("\n", " ", $title))));
                $docs[$i]->content = strtolower($this->removing_white_space($this->remove_hypenated_text(str_replace("\n", " ", $content))));
                $i++;
            }
        }
        return $docs;
    }

    /** FIX
     * Reading a file that contains stop words or common words.
     * @param type $filename
     * @return type an array of string
     */
    public function parse_common_words_to_array($filename) {
        $file = $this->removing_white_space($this->remove_hypenated_text(str_replace("\n", " ", file_get_contents($filename))));
        $file = explode(" ", $file);
        return $file;
    }

    /** FIX
     * Reading a file that contains stop words or common words.
     * @param type $filename
     * @return type string for regex
     */
    public function parse_common_words_to_regex($filename) {
        $file = $this->removing_white_space($this->remove_hypenated_text(str_replace("\n", " ", file_get_contents($filename))));
        $file = implode("|", explode(" ", $file));
        return $file;
    }

    /** FIX
     * reading a file that contains list of query
     * @param type $filename
     * @return type an array of query. The Stucture is "no","query".
     */
    public function parse_query_to_objects($filename) {
        $file = file_get_contents($filename);
        //Parse into n Query
        $queries = explode("\n.I", $file);
        //For each query parse its number
        //parse the query text
        $i = 0;
        $queries_text;
        foreach ($queries as $query) {
            $query_text = explode(".I", $query);
            if (sizeof($query_text) == 2) {
                $number = explode(".W", $query_text[1]);
            } else {
                $number = explode(".W", $query_text[0]);
            }
            //$number[0] is the number of query
            if (sizeof($number) == 2) {
                $text = explode(".N", $number[1]);
                $text = explode(".A", $text[0]);
            } else {
                $text[0] = "";
            }
            //$text[0] is the query text
            $queries_text[$i]->no = $i + 1;
            $queries_text[$i]->query = strtolower(str_replace("\n", " ", $text[0]));
            $i++;
        }
        return $queries_text;
    }

    /** FIX
     * reading a file that contains list of query, reading mark will be eliminated.
     * @param type $filename
     * @return type an array of query. The Stucture is "no","query".
     */
    public function parse_query_to_objects_clean($filename) {
        $file = file_get_contents($filename);
        //Parse into n Query
        $queries = explode("\n.I", $file);
        //For each query parse its number
        //parse the query text
        $i = 0;
        $queries_text;
        foreach ($queries as $query) {
            $query_text = explode(".I", $query);
            if (sizeof($query_text) == 2) {
                $number = explode(".W", $query_text[1]);
            } else {
                $number = explode(".W", $query_text[0]);
            }
            //$number[0] is the number of query
            if (sizeof($number) == 2) {
                $text = explode(".N", $number[1]);
                $text = explode(".A", $text[0]);
            } else {
                $text[0] = "";
            }
            //$text[0] is the query text
            $queries_text[$i]->no = $i + 1;
            $queries_text[$i]->query = strtolower($this->removing_white_space($this->remove_hypenated_text(str_replace("\n", " ", $text[0]))));
            $i++;
        }
        return $queries_text;
    }

    /**
     * parse docs to array of docs that consists of number query and number document that relevant
     * @param type $filename
     * @return type
     */
    public function docs_to_object_of_docs_qrel($filename) {
        $file = file_get_contents($filename);
        // parse each row of file
        $documents = explode("\n", $file);
        $i = 0;
        $docs;
        // inisialisasi array of document
        $item_doc = array();
        foreach ($documents as $document) {
            // parse each component of row
            $number = explode(" ", $document);
            $number[0] = $number[0] - 1;
            if ((int) $number[0] == $i) {
                // push document to array of document
                array_push($item_doc, $number[1]);
            } else {
                // make array query and document
                $item = array(
                    "no_query" => preg_replace("/\n/", ' ', $number[0]),
                    "no_document" => $item_doc
                );
                $docs[$i] = $item;
                // clear array of document for new query
                unset($item_doc);
                $item_doc = array();
                $i++;
                // push top document for new query
                if ((int) $number[0] == $i) {
                    array_push($item_doc, $number[1]);
                }
            }
        }
        return $docs;
    }

    /**
     * ===================================================DOCUMENT PROCESSING FUNCTION========================
     */

    /** FIX
     * Removing hypenated text
     * @param type $text
     * @return type return a text that all punctuations have been removed.
     */
    private function remove_hypenated_text($text) {
        $hypenated = array(
            "~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "=", "{", "}", '[', "]", "\\", "|", ":", ";", '"', "<", ">", ".", ",", "/", "?", "'", "-"
        );
        $cleaned_sign = str_replace($hypenated, " ", $text);
        return $cleaned_sign;
    }

    /** FIX
     * Removing white space and unused space. The main purpose is to separate each word with one space
     * @param type $text
     * @return type a text or string
     */
    private function removing_white_space($text) {
        $term = explode(' ', $text);
        $ret_term = "";
        $j = 0;
        for ($i = 0; $i < sizeof($term); ++$i) {
            if ($term[$i] != null && $term[$i] != " " && $term[$i] != "\n") {
                if ($j != 0) {
                    $ret_term = $ret_term . " " . $term[$i];
                } else {
                    $ret_term = $term[$i];
                }
                ++$j;
            }
        }
        return $ret_term;
    }

    /** FIX
     * Removing common words in text
     * @param type $text
     * @param type $common_words array of common words
     * @return type a text or string that all common words have been removed.
     */
    public function remove_common_words_from_array($text, $common_words) {
        $text = $this->removing_white_space(preg_replace('/\b(' . implode('|', $common_words) . ')\b/i', '', $text));
        return $text;
    }

    /** FIX
     * Removing common words in text
     * @param type $text
     * @param type $common_words regex of common words
     * @return type a text or string that all common words have been removed.
     */
    public function remove_common_words_from_regex($text, $common_words) {
        $text = $this->removing_white_space(preg_replace('/\b(' . $common_words . ')\b/i', '', $text));
        unset($common_words);
        return $text;
    }

    /**
     * ==============================================PERFORM FUNCTION ON DOCUMENTS OR QUERY==========================
     */

    /** FIX
     * Removing hypenated text in all documents
     * @param type $object_docs 
     */
    public function extract_objects_of_doc($object_docs) {
        for ($i = 0; $i < sizeof($object_docs); ++$i) {
            $object_docs[$i]->title = $this->removing_white_space($this->remove_hypenated_text($object_docs[$i]->title));
            $object_docs[$i]->content = $this->removing_white_space($this->remove_hypenated_text($object_docs[$i]->content));
        }
        return $object_docs;
    }

    /** FIX
     * Removing hypenated text in all queries
     * @param type $object_docs 
     */
    public function extract_objects_of_query($queries) {
        for ($i = 0; $i < sizeof($queries); ++$i) {
            $queries[$i]->query = $this->removing_white_space($this->remove_hypenated_text($queries[$i]->query));
        }
        return $queries;
    }

    /** FIX
     * removing common words from object docs, the hypenated text is also being removed
     * @param type $object_docs
     * @param type $common_words
     * @return type $object_docs
     */
    public function docs_remove_common_words_array($object_docs, $common_words) {
        for ($i = 0; $i < sizeof($object_docs); ++$i) {
            $object_docs[$i]->title = $this->remove_common_words_from_array($this->remove_hypenated_text($object_docs[$i]->title), $common_words);
            $object_docs[$i]->content = $this->remove_common_words_from_array($this->remove_hypenated_text($object_docs[$i]->content), $common_words);
        }
        return $object_docs;
    }

    /** FIX
     * removing common words from object docs, the hypenated text is also being removed
     * @param type $object_docs
     * @param type $common_words in string regex
     * @return type $object_docs
     */
    public function docs_remove_common_words_regex($object_docs, $common_words) {
        for ($i = 0; $i < sizeof($object_docs); ++$i) {
            $object_docs[$i]->title = $this->remove_common_words_from_regex($this->remove_hypenated_text($object_docs[$i]->title), $common_words);
            $object_docs[$i]->content = $this->remove_common_words_from_regex($this->remove_hypenated_text($object_docs[$i]->content), $common_words);
        }
        return $object_docs;
    }

    /** NO
     * removing common words from object docs, the hypenated text is also being removed
     * @param type $object_docs
     * @param type $common_words in string regex
     * @return type $object_docs
     */
    public function docs_remove_common_words_json($object_docs, $common_words) {
        for ($i = 0; $i < sizeof($object_docs); ++$i) {
            $object_docs[$i] = json_decode(preg_replace('/\b(' . implode('|', $common_words) . ')\b/i', '', json_encode($object_docs[$i])));
        }
        return $object_docs;
    }

    /** FIX
     * removing common words from object docs, the hypenated text is also being removed
     * @param type $object_docs
     * @param type $common_words
     * @return type $object_docs
     */
    public function query_remove_common_words_array($object_docs, $common_words) {
        for ($i = 0; $i < sizeof($object_docs); ++$i) {
            $object_docs[$i]->query = $this->remove_common_words_from_array($this->remove_hypenated_text($object_docs[$i]->query), $common_words);
        }
        return $object_docs;
    }

    /** FIX
     * removing common words from object docs, the hypenated text is also being removed
     * @param type $object_docs
     * @param type $common_words
     * @return type $object_docs
     */
    public function query_remove_common_words_regex($object_docs, $common_words) {
        for ($i = 0; $i < sizeof($object_docs); ++$i) {
            $object_docs[$i]->query = $this->remove_common_words_from_regex($this->remove_hypenated_text($object_docs[$i]->query), $common_words);
        }
        return $object_docs;
    }

    /** ========================================= PART RESPONSE =============================
     * part respon ajax
     */

    /** FIX
     * parse docs to array of docs and find a document based on the number document on function parameter
     * @param type $filename=nama default "doc.all", $no_doc
     * @return type an array of object docs. The structure is "no","content"
     */
    public function find_document($no_doc) {
        //$no_doc=2;
        $filename = base_url() . "upload/doc.all";
        $file = file_get_contents($filename);
        //parsed document into n documents
        $documents = explode(".I ", $file);
        //for each documents insert into array
        //1. Find the number of document
        //2. Find title, find content
        $doc = "";
        $found = false;
        for ($i = 0; $i < sizeof($documents) && !$found; ++$i) {
            if ($documents[$i] != "") {
                $number = explode(".T", $documents[$i]);
                //$number[0] is a number documents
                $no = $number[0];
                $title = "";
                $content = "";
                //number[1]is consists of title and content
                $rawtitle = explode(".W", $number[1]);
                //after explode, if there is content size of $title must > 1
                //if size 1 it is only title
                if (sizeof($rawtitle) == 1) {
                    $title = $rawtitle[0];
                } else {
                    $title = $rawtitle[0];
                    $content = $rawtitle[1];
                }
                //Cleaning Process for title
                $title = explode("\n.A", $title);
                $on_title = false;
                $abnormal = false;
                if (sizeof($title) == 2) {
                    $on_title = true;
                } else if (sizeof($title) == 3) {
                    $on_title = true;
                    $abnormal = true;
                }
                $pure_title = explode("\n.B", $title[0]);
                $author = "";
                if ($on_title) {
                    if (!$abnormal) {
                        $author = explode("\n.B", $title[1]);
                        $author = explode("\n.X", $author[0]);
                        $author = explode("\n.N", $author[0]);
                        $author = $author[0];
                    } else {
                        $author = $title[1] . "," . $title[2];
                    }
                }
                $title = $pure_title[0];
                //Cleaning for content
                $content = explode("\n.X", $content);
                $content = explode("\n.N", $content[0]);
                $content = explode("\n.A", $content[0]);
                if (!$on_title && sizeof($content) == 2) {
                    $author = explode("\n.X", $content[1]);
                    $author = explode("\n.N", $author[0]);
                    $author = $author[0];
                }
                $content = explode("\n.B", $content[0]);
                $content = $content[0];
                if ($no == $no_doc) {
                    $doc->no = str_replace("\n", " ", $no);
                    $doc->title = str_replace("\n", " ", $title);
                    $doc->author = str_replace("\n", " ", $author);
                    $doc->content = str_replace("\n", " ", $content);
                    $found = true;
                }
            }
        }
        return json_encode($doc);
    }

    /**
     * ==============================================PERFORM FUNCTION PRECISION, RECALL, NIAP==========================
     */
    public function calculate_performance($retrieved_docs, $relevant_docs) {
        $sum_retrieved_relevant_docs = 0;
        $sum_precision_NIAP = 0;
        for ($i = 0; $i < sizeof($retrieved_docs); ++$i) {
            for ($j = 0; $j < sizeof($relevant_docs); ++$j) {
                if ($retrieved_docs[$i]["no_document"] == $relevant_docs[$j]) {
                    // count sum of document that relevant
                    ++$sum_retrieved_relevant_docs;
                    // count precision of document that relevant for NIAP calculation
                    $doc_i = $i + 1;
                    $precision_retrieved_relevant = $sum_retrieved_relevant_docs / $doc_i;
                    $sum_precision_NIAP = $sum_precision_NIAP + $precision_retrieved_relevant;
                }
            }
        }
        if (sizeof($relevant_docs) != 0) {
            $NIAP = $sum_precision_NIAP / sizeof($relevant_docs);
        } else {
            $NIAP = 0;
        }
        return $NIAP;
    }

    public function calculate_performance_experiment($retrieved_docs, $relevant_docs) {
        $array_performance = array();
        // size of $retrieved_docs and $relevant_docs always same
        for ($i = 0; $i < sizeof($retrieved_docs) - 1; ++$i) {
            // number of query
            $no_query = $i + 1;
            // result of query
            $result_query = $retrieved_docs[$i];
            $relevant_docs_i = $relevant_docs[$i];
            $relevant_docs_j = $relevant_docs_i["no_document"];
            $NIAP = $this->calculate_performance($result_query, $relevant_docs_j);
            $item = array(
                "no_query" => $no_query,
                "result_query" => $result_query,
                "niap" => $NIAP
            );
            array_push($array_performance, $item);
        }
        return $array_performance;
    }

    public function count_average_NIAP($retrieved_docs, $relevant_docs) {
        $sum_average_NIAP = 0;
        for ($i = 0; $i < sizeof($retrieved_docs) - 1; ++$i) {
            $retrieved_docs_i = $retrieved_docs[$i];
            $relevant_docs_i = $relevant_docs[$i];
            $relevant_docs_j = $relevant_docs_i["no_document"];
            $NIAP = $this->calculate_performance($retrieved_docs_i, $relevant_docs_j);
            $sum_average_NIAP += $NIAP;
        }
        $average_NIAP = $sum_average_NIAP / sizeof($retrieved_docs);
        return $average_NIAP;
    }
    
    /** Ngembaliin daftar urutan dokumen.
     */
    public function comp($invfile, $onelala, $n_doc){
        $urutan_doc = Array();
        foreach($onelala as $termOnLala){
            for($i=1;$i<=$n_doc;$i++){
                if (!isset($urutan_doc[$i])){
                    $urutan_doc[$i]["value"] = 0;
                    $urutan_doc[$i]["no_document"] = $i;
                }
                if (!isset($invfile[$termOnLala->the_term])){
                    $urutan_doc[$i]["value"] += 0;
                }else
                    $urutan_doc[$i]["value"] += $invfile[$termOnLala->the_term]->weight[$i]*$termOnLala->weight;
            }
        }
        
        
        $values = array();
        foreach ($urutan_doc as $asc) {
            $values[] = $asc['value'];
        }
        array_multisort($values, SORT_DESC, $urutan_doc);
        return $urutan_doc;
    }
    
    public function compAll($invfile, $lala, $n_doc){
        $urut_urut = Array();
        foreach($lala as $key=>$onelala){
            $urut_urut[$key] = $this->comp($invfile,$onelala,$n_doc);
        }
        return $urut_urut;
    }

    public function tes($invfile, $lala) {
        $tes = $invfile["gold"];
        return $tes;
    }



    public function compute($invfile, $lala) {
        $arraySC = array();
        $arrayNoDoc = array();
        $ndoc = 0;
        foreach ($invfile as $inv) {
            $ndoc = sizeof($inv->weight);
            break;
        }
        for ($i = 0; $i < $ndoc; $i++) {
            $item = array(
                "no" => $i + 1,
                "value" => 0
            );
            array_push($arraySC, $item);
        }

        foreach ($lala as $la) {
            $term = $la->the_term;
            $wq = $la->weight;
            if (isset($invfile[$term])) {
                $obj_inv = $invfile[$term];
                $array_doc = $obj_inv->weight;
                for ($i = 1; $i <= sizeof($array_doc); $i++) {
                    $tempv = $array_doc[$i] * $wq;
                    for ($k = 0; $k < sizeof($arraySC); $k++) {
                        $tempSC = $arraySC[$k];
                        if ($tempSC["no"] == $i) {
                            $arraySC[$k]["value"]+=$tempv;
                        }
                    }
                }
            }
        }

//        foreach ($invfile as $inv) {
//            foreach ($lala as $la) {
//                if (($inv->the_term) == ($la->the_term)) {
//                    $wq = $la->weight;
//                    $arraydoc = $inv->weight;
//                    for ($j = 1; $j <= sizeof($arraydoc); $j++) {
//                        $tempv = $arraydoc[$j] * $wq;
//                        for ($k = 0; $k < sizeof($arraySC); $k++) {
//                            $tempSC = $arraySC[$k];
//                            if ($tempSC["no"] == $j) {
//                                $arraySC[$k]["value"]+=$tempv;
//                            }
//                        }
//                    }
//                }
//            }
//        }


        $values = array();
        foreach ($arraySC as $asc) {
            $values[] = $asc['value'];
        }
        array_multisort($values, SORT_DESC, $arraySC);
        foreach ($arraySC as $arSC) {
            $item = array("no_document" => $arSC["no"]);
            array_push($arrayNoDoc, $item);
        }
        return $arrayNoDoc;
    }


    public function compute_all_sc($invfile, $lala) {
        $arraySC = array();
        for ($i = 1; $i <= sizeof($lala); ++$i) {
            $item = $this->compute($invfile, $lala[$i]);
            array_push($arraySC, $item);
        }
        return $arraySC;
    }

}

?>